<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>拼音点名程序</title>
    <script src="gsap.min.js"></script>
    <style>
        /* Define the custom font */
        @font-face {
            font-family: 'PinyinFont'; /* Custom font name */
            src: url('Mengshen-Handwritten.ttf') format('truetype'); /* Path to your font file */
            font-weight: normal;
            font-style: normal;
        }

        body {
            margin: 0;
            overflow: hidden; /* Prevent scrollbars */
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            background-color: #1a1a2e; /* Dark background */
            font-family: 'Arial', sans-serif; /* Fallback font */
            perspective: 1000px; /* 3D perspective */
            position: relative;
        }

        /* Container for info display (student ID/Name) */
        .info-display-container {
            position: absolute;
            top: 75%; /* Position adjusted to 25% screen height */
            left: 50%;
            transform: translate(-50%, -50%); /* Center horizontally and vertically relative to top: 25% */
            text-align: center;
            color: #e0e0e0;
            z-index: 10; /* Ensure UI elements are above names */
            pointer-events: none; /* Allow clicks to pass through */
        }

        .small-text {
            font-size: 1.2em;
            margin: 0 5px;
        }

        /* Container for file input and roll call button */
        .controls-container {
            position: absolute;
            /* Adjust top to place it below info-display-container */
            top: calc(75% + 50px); /* Relative to new info-display-container position */
            left: 50%;
            transform: translateX(-50%); /* Center horizontally */
            z-index: 10; /* Ensure UI elements are above names */
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 15px; /* Space between elements */
        }

        #rollCallBtn {
            padding: 10px 20px; /* Smaller padding */
            font-size: 1.2em; /* Smaller font size */
            background-color: #0f3460;
            color: #e94560;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            box-shadow: 0 0 15px rgba(233, 69, 96, 0.6);
            transition: background-color 0.3s ease, transform 0.2s ease;
            text-transform: uppercase;
            font-weight: bold;
        }

        #rollCallBtn:hover {
            background-color: #16213e;
            transform: translateY(-2px);
        }

        #rollCallBtn:active {
            transform: translateY(1px);
        }

        #fileInput {
            color: #e0e0e0;
            margin-bottom: 0; /* Removed previous margin */
        }

        .flying-name {
            position: absolute;
            color: #8c7ae6; /* Name color (blue) */
            white-space: nowrap;
            font-weight: bold;
            opacity: 0;
            transform-style: preserve-3d; /* Enable 3D transforms */
            pointer-events: none; /* Avoid blocking mouse events */
            text-shadow: 0 0 10px rgba(140, 122, 230, 0.8); /* Stronger blue shadow */
            font-size: 1em; /* Base font size for scaling */
            font-family: 'PinyinFont', 'Arial', sans-serif; /* Apply custom font */
        }

        .selected-name {
            position: absolute;
            color: #8c7ae6; /* Color for the selected name (blue) */
            font-weight: bold;
            text-shadow: 0 0 20px rgba(140, 122, 230, 0.9); /* Blue shadow */
            text-align: center;
            white-space: nowrap;
            pointer-events: none;
            z-index: 5; /* Above other flying names */
            font-size: 1em; /* Base font size for scaling */
            font-family: 'PinyinFont', 'Arial', sans-serif; /* Apply custom font */
        }

        /* Custom Message Box Styles */
        .message-box {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background-color: #2c3e50;
            color: #e0e0e0;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
            z-index: 1000;
            display: none; /* Hidden by default */
            text-align: center;
        }

        .message-box p {
            margin-bottom: 15px;
            font-size: 1.1em;
        }

        .message-box button {
            padding: 10px 20px;
            background-color: #e94560;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 1em;
            transition: background-color 0.3s ease;
        }

        .message-box button:hover {
            background-color: #c2314d;
        }
    </style>
</head>
<body>
    <!-- Info display for selected student (positioned at 75% height) -->
    <div class="info-display-container">
        <span id="studentInfoDisplay" class="small-text"></span>
    </div>

    <!-- Control buttons (positioned at the bottom) -->
    <div class="controls-container">
        <input type="file" id="fileInput" accept=".txt">
        <button id="rollCallBtn">点名</button>
    </div>

    <!-- Custom Message Box HTML -->
    <div id="messageBox" class="message-box">
        <p id="messageText"></p>
        <button id="messageBoxCloseBtn">确定</button>
    </div>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const fileInput = document.getElementById('fileInput');
            const rollCallBtn = document.getElementById('rollCallBtn');
            const studentInfoDisplay = document.getElementById('studentInfoDisplay'); // Merged display element

            const messageBox = document.getElementById('messageBox');
            const messageText = document.getElementById('messageText');
            const messageBoxCloseBtn = document.getElementById('messageBoxCloseBtn');

            let students = []; // Stores student data { id: '学号', name: '姓名' }
            const ANIMATION_DURATION = 6; // Total animation duration (seconds)
            const RELEASE_DURATION_PERCENT = 0.5; // 50% of total duration for releasing all names
            const FLIGHT_DURATION_PERCENT = 0.5; // 50% of total duration for each name's flight

            // Function to show custom message box
            function showMessageBox(message) {
                messageText.textContent = message;
                messageBox.style.display = 'block';
            }

            // Event listener for closing message box
            messageBoxCloseBtn.addEventListener('click', () => {
                messageBox.style.display = 'none';
            });

            // Fisher-Yates shuffle algorithm
            function shuffleArray(array) {
                for (let i = array.length - 1; i > 0; i--) {
                    const j = Math.floor(Math.random() * (i + 1));
                    [array[i], array[j]] = [array[j], array[i]];
                }
                return array;
            }

            // --- File loading ---
            fileInput.addEventListener('change', (event) => {
                const file = event.target.files[0];
                if (file) {
                    const reader = new FileReader();
                    reader.onload = (e) => {
                        const text = e.target.result;
                        students = text.split('\n').map(line => {
                            // Updated to support tab (\t), comma, ideographic comma, or space separation
                            const parts = line.trim().split(/[,，\s\t]+/);
                            if (parts.length >= 2) {
                                return { id: parts[0], name: parts[1] };
                            }
                            return null;
                        }).filter(Boolean); // Filter out invalid lines
                        if (students.length > 0) {
                            rollCallBtn.disabled = false;
                            console.log('Student data loaded successfully:', students);
                        } else {
                            rollCallBtn.disabled = true;
                            showMessageBox('文件内容为空或格式不正确，请确保每行包含学号和姓名，并使用逗号、空格或制表符分隔。');
                        }
                    };
                    reader.readAsText(file);
                }
            });

            // --- Roll Call button click event ---
            rollCallBtn.addEventListener('click', () => {
                if (students.length === 0) {
                    showMessageBox('请先上传学生名单！');
                    return;
                }

                // Disable button to prevent multiple clicks
                rollCallBtn.disabled = true;
                rollCallBtn.textContent = '点名中...';

                // Clear previous name elements
                document.querySelectorAll('.flying-name').forEach(el => el.remove());
                document.querySelectorAll('.selected-name').forEach(el => el.remove());

                studentInfoDisplay.textContent = ''; // Clear combined display

                // Shuffle the students array and mark the last one as final
                const shuffledStudents = shuffleArray([...students]); // Create a shallow copy to shuffle
                const finalStudent = shuffledStudents[shuffledStudents.length - 1];

                // Calculate target scale for the final large size ONCE
                // Create a dummy element to get computed style for base font size
                const tempNameElement = document.createElement('div');
                tempNameElement.classList.add('flying-name'); // Use the same class for styling
                tempNameElement.textContent = finalStudent.name;
                document.body.appendChild(tempNameElement); // Temporarily add to DOM to get computed style
                const baseFontSize = parseFloat(getComputedStyle(tempNameElement).fontSize);
                tempNameElement.remove(); // Remove it immediately

                const targetWidth = window.innerWidth * 0.36; // Target width is 50% of window width
                const estimatedTextWidthAtScale1 = finalStudent.name.length * (baseFontSize * 0.8); // Rough estimate
                const finalTargetScale = Math.max(1, targetWidth / estimatedTextWidthAtScale1); // Ensure scale is at least 1

                // --- Create and animate all names ---
                const totalNamesToRelease = shuffledStudents.length;
                const releaseInterval = (ANIMATION_DURATION * RELEASE_DURATION_PERCENT) / (totalNamesToRelease - 1 || 1); // Time between releasing each name

                shuffledStudents.forEach((student, index) => {
                    const isFinal = (student === finalStudent); // Check if this is the final student
                    const releaseDelay = index * releaseInterval; // Calculate release delay for each name

                    createFlyingName(student, isFinal, finalTargetScale, releaseDelay);
                });
            });

            // --- Create a flying name element ---
            function createFlyingName(student, isFinal, sharedTargetScale, releaseDelay) {
                const nameElement = document.createElement('div');
                nameElement.classList.add('flying-name');
                nameElement.textContent = student.name;
                document.body.appendChild(nameElement);

                // Random initial position and size
                const startX = Math.random() * window.innerWidth - window.innerWidth / 2;
                const startY = Math.random() * window.innerHeight - window.innerHeight / 2;
                const startZ = -2000 - Math.random() * 3000; // Start from very far away
                const initialScale = 0.05 + Math.random() * 0.1; // Very small initial size

                gsap.set(nameElement, {
                    x: startX,
                    y: startY,
                    z: startZ,
                    scale: initialScale,
                    opacity: 0
                    // Removed rotation properties for all names
                });

                const tl = gsap.timeline({
                    delay: releaseDelay, // Start the animation after the calculated release delay
                    onComplete: () => {
                        if (isFinal) {
                            // Only for the final name, update display and re-enable button
                            nameElement.classList.remove('flying-name');
                            nameElement.classList.add('selected-name');

                            // Update the combined display
                            studentInfoDisplay.textContent = `${student.id}   ${student.name}`;

                            rollCallBtn.disabled = false;
                            rollCallBtn.textContent = '点名';
                        } else {
                            // Remove non-final names after they fly out
                            nameElement.remove();
                        }
                    }
                });

                // All names fly towards the center, scaling up
                tl.to(nameElement, {
                    duration: ANIMATION_DURATION * FLIGHT_DURATION_PERCENT, // Each name's flight duration (3 seconds)
                    x: 0, // Fly to center X
                    y: 0, // Fly to center Y
                    z: 0, // Fly to front
                    // Reverted scale for non-final names to have a random range around sharedTargetScale
                    // scale: isFinal ? sharedTargetScale : (sharedTargetScale * (0.8 + Math.random() * 0.4)),
                    scale: sharedTargetScale,
                    opacity: isFinal ? 1 : 0, // Final name stays opaque, others disappear
                    ease: "power2.out"
                })
                // Fade in during the initial part of the flight for all names
                .fromTo(nameElement,
                    { opacity: 0 },
                    { opacity: 1, duration: (ANIMATION_DURATION * FLIGHT_DURATION_PERCENT) * 0.3, ease: "power1.in" },
                    0); // Start fade-in at the beginning of its flight

                // For non-final names, add a fade-out towards the end of their flight
                if (!isFinal) {
                    tl.to(nameElement, {
                        opacity: 0,
                        duration: (ANIMATION_DURATION * FLIGHT_DURATION_PERCENT) * 0.3, // Fade out over last 30% of its flight
                        ease: "power1.out"
                    }, (ANIMATION_DURATION * FLIGHT_DURATION_PERCENT) * 0.7); // Start fade-out at 70% of its flight duration
                }
            }

            // Initial disable the roll call button until file is loaded
            rollCallBtn.disabled = true;
        });
    </script>
</body>
</html>
